import { Request, Response, NextFunction } from 'express';
import bcrypt from 'bcryptjs';
import jwt, { SignOptions } from 'jsonwebtoken';
import { prisma } from '../../config/database';
import config, { ConfigUtils } from '@/config';
import { BaseController } from '../../utils/autoBind';
import { ResponseUtils } from '../../utils/responseUtils';
import { 
  BUSINESS_ERROR_CODES, 
  AUTH_ERROR_CODES
} from '../../utils/errorCodes';

export class ClientAuthController extends BaseController {
  // 用户注册
  async register(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { username, email, password, realName, phone } = req.body;

      // 检查用户名是否已存在
      const existingUser = await prisma.user.findFirst({
        where: {
          OR: [
            { username },
            { email }
          ]
        }
      });

      if (existingUser) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_ALREADY_EXISTS, '用户名或邮箱已存在');
        return;
      }

      // 加密密码
      const saltRounds = ConfigUtils.getBcryptRounds();
      const hashedPassword = await bcrypt.hash(password, saltRounds);

      // 创建用户
      const user = await prisma.user.create({
        data: {
          username,
          email,
          password: hashedPassword,
          realName,
          phone
        },
        select: {
          id: true,
          username: true,
          email: true,
          realName: true,
          avatar: true,
          phone: true,
          status: true,
          createdAt: true
        }
      });

      // 生成JWT令牌
      const token = this.generateToken(user.id);
      const refreshToken = this.generateRefreshToken(user.id);

      ResponseUtils.created(res, {
        user,
        token,
        refreshToken
      }, '注册成功');
    } catch (error) {
      next(error);
    }
  }

  // 用户登录
  async login(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { username, password } = req.body;

      // 查找用户
      const user = await prisma.user.findFirst({
        where: {
          OR: [
            { username },
            { email: username }
          ]
        }
      });

      if (!user) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户名或密码错误');
        return;
      }

      // 验证密码
      const isPasswordValid = await bcrypt.compare(password, user.password);
      if (!isPasswordValid) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.PASSWORD_INCORRECT, '用户名或密码错误');
        return;
      }

      // 检查用户状态
      if (user.status !== 'ACTIVE') {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_DISABLED, '账户已被禁用');
        return;
      }

      // 更新最后登录时间
      await prisma.user.update({
        where: { id: user.id },
        data: { lastLoginAt: new Date() }
      });

      // 生成JWT令牌
      const token = this.generateToken(user.id);
      const refreshToken = this.generateRefreshToken(user.id);

      // 构建用户信息（不包含密码）
      const userInfo = {
        id: user.id,
        username: user.username,
        email: user.email,
        realName: user.realName,
        avatar: user.avatar,
        phone: user.phone,
        status: user.status,
        lastLoginAt: user.lastLoginAt,
        createdAt: user.createdAt
      };

      ResponseUtils.success(res, {
        user: userInfo,
        token,
        refreshToken
      }, '登录成功');
    } catch (error) {
      next(error);
    }
  }

  // 用户登出
  async logout(_req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      // 这里可以添加令牌黑名单逻辑
      ResponseUtils.success(res, null, '登出成功');
    } catch (error) {
      next(error);
    }
  }

  // 刷新访问令牌
  async refreshToken(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      if (!req.user) {
        ResponseUtils.sendError(res, AUTH_ERROR_CODES.TOKEN_MISSING, '用户未认证');
        return;
      }

      // 检查是否为游客用户
      if (req.user.isGuest) {
        ResponseUtils.sendError(res, AUTH_ERROR_CODES.TOKEN_MISSING, '游客用户不支持刷新令牌');
        return;
      }

      // 生成新的访问令牌
      const newToken = this.generateToken(req.user.id as number);
      const newRefreshToken = this.generateRefreshToken(req.user.id as number);

      ResponseUtils.success(res, {
        token: newToken,
        refreshToken: newRefreshToken
      }, '令牌刷新成功');
    } catch (error) {
      next(error);
    }
  }

  // 获取当前用户信息
  async getProfile(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      if (!req.user) {
        ResponseUtils.sendError(res, AUTH_ERROR_CODES.TOKEN_MISSING, '用户未认证');
        return;
      }

      // 检查是否为游客用户
      if (req.user.isGuest) {
        // 游客用户直接返回游客信息，无需查询数据库
        const guestInfo = {
          id: req.user.id,
          username: '游客',
          email: null,
          realName: '游客用户',
          avatar: null,
          phone: null,
          status: 'ACTIVE',
          isGuest: true,
          lastLoginAt: new Date(),
          createdAt: new Date(),
          roles: [
            {
              id: 'guest_role',
              name: '游客',
              description: '临时游客用户',
              permissions: [
                {
                  id: 'guest_basic',
                  code: 'GUEST_BASIC',
                  name: '基础访问权限',
                  module: 'guest'
                }
              ]
            }
          ]
        };

        ResponseUtils.success(res, guestInfo, '获取游客信息成功');
        return;
      }

      const user = await prisma.user.findUnique({
        where: { id: req.user.id as number },
        include: {
          userRoles: {
            include: {
              role: {
                include: {
                  rolePermissions: {
                    include: {
                      permission: true
                    }
                  }
                }
              }
            }
          }
        }
      });

      if (!user) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      // 构建用户信息
      const userInfo = {
        id: user.id,
        username: user.username,
        email: user.email,
        realName: user.realName,
        avatar: user.avatar,
        phone: user.phone,
        status: user.status,
        lastLoginAt: user.lastLoginAt,
        createdAt: user.createdAt,
        roles: user.userRoles.map((ur: any) => ({
          id: ur.role.id,
          name: ur.role.name,
          description: ur.role.description,
          permissions: ur.role.rolePermissions.map((rp: any) => ({
            id: rp.permission.id,
            code: rp.permission.code,
            name: rp.permission.name,
            module: rp.permission.module
          }))
        }))
      };

      ResponseUtils.success(res, userInfo, '获取用户信息成功');
    } catch (error) {
      next(error);
    }
  }

  // 修改密码
  async changePassword(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      if (!req.user) {
        ResponseUtils.sendError(res, AUTH_ERROR_CODES.TOKEN_MISSING, '用户未认证');
        return;
      }

      // 检查是否为游客用户
      if (req.user.isGuest) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.PASSWORD_INCORRECT, '游客用户不支持修改密码');
        return;
      }

      const { currentPassword, newPassword } = req.body;

      if (!currentPassword || !newPassword) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.PASSWORD_INCORRECT, '当前密码和新密码不能为空');
        return;
      }

      const user = await prisma.user.findUnique({
        where: { id: req.user.id as number }
      });

      if (!user) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      // 验证当前密码
      const isCurrentPasswordValid = await bcrypt.compare(currentPassword, user.password);
      if (!isCurrentPasswordValid) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.PASSWORD_INCORRECT, '当前密码错误');
        return;
      }

      // 加密新密码
      const saltRounds = ConfigUtils.getBcryptRounds();
      const hashedNewPassword = await bcrypt.hash(newPassword, saltRounds);

      // 更新密码
      await prisma.user.update({
        where: { id: req.user.id as number },
        data: { password: hashedNewPassword }
      });

      ResponseUtils.success(res, null, '密码修改成功');
    } catch (error) {
      next(error);
    }
  }

  // 游客登录
  async guestLogin(_req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      // 生成游客ID（使用时间戳+随机数，但转换为数字以避免类型冲突）
      const timestamp = Date.now();
      const randomPart = Math.floor(Math.random() * 1000000);
      const guestId = parseInt(`${timestamp}${randomPart}`.slice(-9)); // 生成9位数字ID
      
      // 生成游客令牌（有效期较短，通常24小时）
      const guestToken = jwt.sign(
        { 
          id: guestId, 
          type: 'guest',
          isGuest: true 
        },
        config.jwt.secret,
        { expiresIn: '24h' } as SignOptions
      );

      // 构建游客信息
      const guestInfo = {
        id: guestId,
        username: '游客',
        email: null,
        realName: '游客用户',
        avatar: null,
        phone: null,
        status: 'ACTIVE',
        isGuest: true,
        lastLoginAt: new Date(),
        createdAt: new Date(),
        roles: [
          {
            id: 'guest_role',
            name: '游客',
            description: '临时游客用户',
            permissions: [
              {
                id: 'guest_basic',
                code: 'GUEST_BASIC',
                name: '基础访问权限',
                module: 'guest'
              }
            ]
          }
        ]
      };

      ResponseUtils.success(res, {
        user: guestInfo,
        token: guestToken,
        refreshToken: null // 游客不需要刷新令牌
      }, '游客登录成功');
    } catch (error) {
      next(error);
    }
  }

  // 生成访问令牌
  private generateToken(userId: number): string {
    return jwt.sign(
      { id: userId },
      config.jwt.secret,
      { expiresIn: config.jwt.expiresIn || '7d' } as SignOptions
    );
  }

  // 生成刷新令牌
  private generateRefreshToken(userId: number): string {
    return jwt.sign(
      { id: userId, type: 'refresh' },
      config.jwt.secret,
      { expiresIn: config.jwt.refreshExpiresIn || '30d' } as SignOptions
    );
  }
} 